bitkeeper revision 1.795 (4054a3055ggg3MJTpSU1-ZFQRfQQ5g)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 14 Mar 2004 18:23:01 +0000 (18:23 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sun, 14 Mar 2004 18:23:01 +0000 (18:23 +0000)
xend.py, setup.py:
  new file
Many files:
  Rewritten the Xen control daemon in Python, with C extensions for the low-level bits. All our Python libraries now throw exceptions on error rather than returning error codes --- this will require our higher-level scripts to be updated at some point.

12 files changed:
.rootkeys
tools/examples/xc_dom_create.py
tools/xc/py/Makefile
tools/xc/py/Xc.c
tools/xc/py/XenoUtil.py
tools/xend/Makefile
tools/xend/setup.py [new file with mode: 0644]
tools/xend/xend.py [new file with mode: 0755]
tools/xend/xend_utils.c
tools/xentrace/Makefile
xenolinux-2.4.25-sparse/arch/xeno/drivers/console/console.c
xenolinux-2.4.25-sparse/include/asm-xeno/control_if.h

index e078d7cc52100ec9cf7e7d97fb99ff710f21a1f7..c090dc8fd40c3c0731a20c7436f4953814d8b1a4 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
@@ -89,6 +89,8 @@
 3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xc/py/XenoUtil.py
 3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py
 40431ac64Hj4ixUnKmlugZKhXPFE_Q tools/xend/Makefile
+4054a2fdkdATEnRw-U7AUlgu-6JiUA tools/xend/setup.py
+4054a301VEag2GwrBrFBna5U1BGlLA tools/xend/xend.py
 40431ac8wrUEj-XM7B8smFtx_HA7lQ tools/xend/xend_utils.c
 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
 4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xentrace/xentrace.8
index 4af0d9b0da822a1b10ba652f0d4db324d0b56488..94f37a4494fa6d022a256e7c380b35baa29ca4f2 100755 (executable)
@@ -237,9 +237,14 @@ def make_domain():
             xc.domain_destroy ( dom=id )
             sys.exit()
 
-    ports = xc.evtchn_open( dom2=id )
-    if not ports:
+    cmsg = 'new_control_interface(dom='+str(id)+')'
+    xend_response = XenoUtil.xend_control_message(cmsg)
+    if not xend_response['success']:
         print "Error creating initial event channel"
+        print "Error type: " + xend_response['error_type']
+        if xend_response['error_type'] == 'exception':
+            print "Exception type: " + xend_response['exception_type']
+            print "Exception value: " + xend_response['exception_value']
         xc.domain_destroy ( dom=id )
         sys.exit()
 
@@ -292,7 +297,7 @@ def make_domain():
         xc.domain_destroy ( dom=id )
         sys.exit()
 
-    return (id, 9600+ports['port1'])
+    return (id, xend_response['console_port'])
 # end of make_domain()
 
 def mkpidfile():
index 058450e0dc35c38c7edc5febb268a12065123541..9f66e3c05e6f1a2f390353c06866608a93584df6 100644 (file)
@@ -1,5 +1,5 @@
 
-all: ../lib/libxc.so.1.3.0 ../lib/xc.h
+all:
        python setup.py build
 
 install: all
index 3515047ee9f08e81c612519c5f5e42c52e47bb80..124942bbb0271bce6dbe570b9c6deefaf703edd7 100644 (file)
@@ -1,19 +1,13 @@
 /******************************************************************************
  * Xc.c
  * 
- * Copyright (c) 2003, K A Fraser
+ * Copyright (c) 2003-2004, K A Fraser (University of Cambridge)
  */
 
 #include <Python.h>
 #include <xc.h>
 
-#if 1
-#define DPRINTF(_f, _a...)                  \
-    fprintf(stderr, "%s:%s:%d:: " _f "\n" , \
-            __FILE__ , __FUNCTION__ , __LINE__ , ## _a)
-#else
-#define DPRINTF(_f, _a...) ((void)0)
-#endif
+static PyObject *xc_error, *zero;
 
 typedef struct {
     PyObject_HEAD;
@@ -39,13 +33,10 @@ static PyObject *pyxc_domain_create(PyObject *self,
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|is", kwd_list, 
                                       &mem_kb, &name) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
     if ( (ret = xc_domain_create(xc->xc_handle, mem_kb, name, &dom)) < 0 )
-        return PyLong_FromLong(ret);
+        return PyErr_SetFromErrno(xc_error);
 
     return PyLong_FromUnsignedLongLong(dom);
 }
@@ -57,19 +48,17 @@ static PyObject *pyxc_domain_start(PyObject *self,
     XcObject *xc = (XcObject *)self;
 
     u64 dom;
-    int ret;
 
     static char *kwd_list[] = { "dom", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &dom) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_domain_start(xc->xc_handle, dom);
+    if ( xc_domain_start(xc->xc_handle, dom) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_domain_stop(PyObject *self,
@@ -79,19 +68,17 @@ static PyObject *pyxc_domain_stop(PyObject *self,
     XcObject *xc = (XcObject *)self;
 
     u64 dom;
-    int ret;
 
     static char *kwd_list[] = { "dom", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L", kwd_list, &dom) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_domain_stop(xc->xc_handle, dom);
+    if ( xc_domain_stop(xc->xc_handle, dom) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_domain_destroy(PyObject *self,
@@ -101,20 +88,19 @@ static PyObject *pyxc_domain_destroy(PyObject *self,
     XcObject *xc = (XcObject *)self;
 
     u64 dom;
-    int force = 0, ret;
+    int force = 0;
 
     static char *kwd_list[] = { "dom", "force", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwd_list, 
                                       &dom, &force) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_domain_destroy(xc->xc_handle, dom, force);
+    if ( xc_domain_destroy(xc->xc_handle, dom, force) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_domain_pincpu(PyObject *self,
@@ -124,20 +110,19 @@ static PyObject *pyxc_domain_pincpu(PyObject *self,
     XcObject *xc = (XcObject *)self;
 
     u64 dom;
-    int cpu = -1, ret;
+    int cpu = -1;
 
     static char *kwd_list[] = { "dom", "cpu", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwd_list, 
                                       &dom, &cpu) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_domain_pincpu(xc->xc_handle, dom, cpu);
+    if ( xc_domain_pincpu(xc->xc_handle, dom, cpu) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_domain_getinfo(PyObject *self,
@@ -155,20 +140,12 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
     
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|Li", kwd_list,
                                       &first_dom, &max_doms) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
     if ( (info = malloc(max_doms * sizeof(xc_dominfo_t))) == NULL )
-    {
-        DPRINTF("out of memory.");
-        nr_doms = 0;
-    }
-    else
-    {
-        nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info);
-    }
+        return PyErr_NoMemory();
+
+    nr_doms = xc_domain_getinfo(xc->xc_handle, first_dom, max_doms, info);
     
     list = PyList_New(nr_doms);
     for ( i = 0 ; i < nr_doms; i++ )
@@ -185,8 +162,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
                           "name",     info[i].name));
     }
 
-    if ( info != NULL )
-        free(info);
+    free(info);
 
     return list;
 }
@@ -199,20 +175,19 @@ static PyObject *pyxc_linux_save(PyObject *self,
 
     u64   dom;
     char *state_file;
-    int   progress = 1, ret;
+    int   progress = 1;
 
     static char *kwd_list[] = { "dom", "state_file", "progress", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|i", kwd_list, 
                                       &dom, &state_file, &progress) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_linux_save(xc->xc_handle, dom, state_file, progress);
+    if ( xc_linux_save(xc->xc_handle, dom, state_file, progress) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_linux_restore(PyObject *self,
@@ -222,21 +197,17 @@ static PyObject *pyxc_linux_restore(PyObject *self,
     XcObject *xc = (XcObject *)self;
 
     char        *state_file;
-    int          progress = 1, ret;
+    int          progress = 1;
     u64          dom;
 
     static char *kwd_list[] = { "state_file", "progress", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwd_list, 
                                       &state_file, &progress) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_linux_restore(xc->xc_handle, state_file, progress, &dom);
-    if ( ret < 0 )
-        return PyLong_FromLong(ret);
+    if ( xc_linux_restore(xc->xc_handle, state_file, progress, &dom) != 0 )
+        return PyErr_SetFromErrno(xc_error);
 
     return PyLong_FromUnsignedLongLong(dom);
 }
@@ -249,20 +220,18 @@ static PyObject *pyxc_linux_build(PyObject *self,
 
     u64   dom;
     char *image, *ramdisk = NULL, *cmdline = "";
-    int   ret;
 
     static char *kwd_list[] = { "dom", "image", "ramdisk", "cmdline", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|ss", kwd_list, 
                                       &dom, &image, &ramdisk, &cmdline) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_linux_build(xc->xc_handle, dom, image, ramdisk, cmdline);
+    if ( xc_linux_build(xc->xc_handle, dom, image, ramdisk, cmdline) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_netbsd_build(PyObject *self,
@@ -273,20 +242,18 @@ static PyObject *pyxc_netbsd_build(PyObject *self,
 
     u64   dom;
     char *image, *ramdisk = NULL, *cmdline = "";
-    int   ret;
 
     static char *kwd_list[] = { "dom", "image", "ramdisk", "cmdline", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|ss", kwd_list, 
                                       &dom, &image, &ramdisk, &cmdline) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_netbsd_build(xc->xc_handle, dom, image, cmdline);
+    if ( xc_netbsd_build(xc->xc_handle, dom, image, cmdline) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_bvtsched_global_set(PyObject *self,
@@ -296,19 +263,17 @@ static PyObject *pyxc_bvtsched_global_set(PyObject *self,
     XcObject *xc = (XcObject *)self;
 
     unsigned long ctx_allow;
-    int           ret;
 
     static char *kwd_list[] = { "ctx_allow", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "l", kwd_list, &ctx_allow) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_bvtsched_global_set(xc->xc_handle, ctx_allow);
+    if ( xc_bvtsched_global_set(xc->xc_handle, ctx_allow) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_bvtsched_domain_set(PyObject *self,
@@ -319,22 +284,20 @@ static PyObject *pyxc_bvtsched_domain_set(PyObject *self,
 
     u64           dom;
     unsigned long mcuadv, warp, warpl, warpu;
-    int           ret;
 
     static char *kwd_list[] = { "dom", "mcuadv", "warp", "warpl", 
                                 "warpu", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Lllll", kwd_list, 
                                       &dom, &mcuadv, &warp, &warpl, &warpu) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, 
-                                 warp, warpl, warpu);
+    if ( xc_bvtsched_domain_set(xc->xc_handle, dom, mcuadv, 
+                                warp, warpl, warpu) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_vif_scheduler_set(PyObject *self,
@@ -346,7 +309,6 @@ static PyObject *pyxc_vif_scheduler_set(PyObject *self,
     u64           dom;
     unsigned int  vif;
     xc_vif_sched_params_t sched = { 0, 0 };
-    int           ret;
 
     static char *kwd_list[] = { "dom", "vif", "credit_bytes", 
                                 "credit_usecs", NULL };
@@ -355,14 +317,13 @@ static PyObject *pyxc_vif_scheduler_set(PyObject *self,
                                       &dom, &vif, 
                                       &sched.credit_bytes, 
                                       &sched.credit_usec) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_vif_scheduler_set(xc->xc_handle, dom, vif, &sched);
+    if ( xc_vif_scheduler_set(xc->xc_handle, dom, vif, &sched) != 0 )
+        return PyErr_SetFromErrno(xc_error);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_vif_scheduler_get(PyObject *self,
@@ -370,32 +331,23 @@ static PyObject *pyxc_vif_scheduler_get(PyObject *self,
                                         PyObject *kwds)
 {
     XcObject *xc = (XcObject *)self;
-    PyObject *dict;
 
     u64           dom;
     unsigned int  vif;
     xc_vif_sched_params_t sched;
-    int           ret;
 
     static char *kwd_list[] = { "dom", "vif", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, 
                                       &dom, &vif) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_vif_scheduler_get(xc->xc_handle, dom, vif, &sched);
+    if ( xc_vif_scheduler_get(xc->xc_handle, dom, vif, &sched) != 0 )
+        return PyErr_SetFromErrno(xc_error);
 
-    if ( ret < 0 )
-        dict = Py_BuildValue("{}");
-    else
-        dict = Py_BuildValue("{s:l,s:l}", 
-                             "credit_bytes", sched.credit_bytes,
-                             "credit_usecs", sched.credit_usec);
-    
-    return dict;
+    return Py_BuildValue("{s:l,s:l}", 
+                         "credit_bytes", sched.credit_bytes,
+                         "credit_usecs", sched.credit_usec);
 }
 
 static PyObject *pyxc_vif_stats_get(PyObject *self,
@@ -403,34 +355,25 @@ static PyObject *pyxc_vif_stats_get(PyObject *self,
                                     PyObject *kwds)
 {
     XcObject *xc = (XcObject *)self;
-    PyObject *dict;
 
     u64            dom;
     unsigned int   vif;
     xc_vif_stats_t stats;
-    int            ret;
 
     static char *kwd_list[] = { "dom", "vif", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, 
                                       &dom, &vif) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_vif_stats_get(xc->xc_handle, dom, vif, &stats);
+    if ( xc_vif_stats_get(xc->xc_handle, dom, vif, &stats) != 0 )
+        return PyErr_SetFromErrno(xc_error);
 
-    if ( ret < 0 )
-        dict = Py_BuildValue("{}");
-    else
-        dict = Py_BuildValue("{s:L,s:L,s:L,s:L}", 
-                             "tx_bytes", stats.tx_bytes,
-                             "tx_packets", stats.tx_pkts,
-                             "rx_bytes", stats.rx_bytes,
-                             "rx_packets", stats.rx_pkts);
-    
-    return dict;
+    return Py_BuildValue("{s:L,s:L,s:L,s:L}", 
+                         "tx_bytes", stats.tx_bytes,
+                         "tx_packets", stats.tx_pkts,
+                         "rx_bytes", stats.rx_bytes,
+                         "rx_packets", stats.rx_pkts);
 }
 
 static PyObject *pyxc_vbd_create(PyObject *self,
@@ -441,20 +384,19 @@ static PyObject *pyxc_vbd_create(PyObject *self,
 
     u64          dom;
     unsigned int vbd;
-    int          writeable, ret;
+    int          writeable;
 
     static char *kwd_list[] = { "dom", "vbd", "writeable", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Lii", kwd_list, 
                                       &dom, &vbd, &writeable) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_vbd_create(xc->xc_handle, dom, vbd, writeable);
-    
-    return PyInt_FromLong(ret);
+    if ( xc_vbd_create(xc->xc_handle, dom, vbd, writeable) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_vbd_destroy(PyObject *self,
@@ -465,20 +407,18 @@ static PyObject *pyxc_vbd_destroy(PyObject *self,
 
     u64          dom;
     unsigned int vbd;
-    int          ret;
 
     static char *kwd_list[] = { "dom", "vbd", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, 
                                       &dom, &vbd) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_vbd_destroy(xc->xc_handle, dom, vbd);
-    
-    return PyInt_FromLong(ret);
+    if ( xc_vbd_destroy(xc->xc_handle, dom, vbd) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_vbd_grow(PyObject *self,
@@ -490,7 +430,6 @@ static PyObject *pyxc_vbd_grow(PyObject *self,
     u64            dom;
     unsigned int   vbd;
     xc_vbdextent_t extent;
-    int            ret;
 
     static char *kwd_list[] = { "dom", "vbd", "device", 
                                 "start_sector", "nr_sectors", NULL };
@@ -500,14 +439,13 @@ static PyObject *pyxc_vbd_grow(PyObject *self,
                                       &extent.real_device, 
                                       &extent.start_sector, 
                                       &extent.nr_sectors) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_vbd_grow(xc->xc_handle, dom, vbd, &extent);
-    
-    return PyInt_FromLong(ret);
+    if ( xc_vbd_grow(xc->xc_handle, dom, vbd, &extent) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_vbd_shrink(PyObject *self,
@@ -518,20 +456,18 @@ static PyObject *pyxc_vbd_shrink(PyObject *self,
 
     u64          dom;
     unsigned int vbd;
-    int          ret;
 
     static char *kwd_list[] = { "dom", "vbd", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, 
                                       &dom, &vbd) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_vbd_shrink(xc->xc_handle, dom, vbd);
-    
-    return PyInt_FromLong(ret);
+    if ( xc_vbd_shrink(xc->xc_handle, dom, vbd) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_vbd_setextents(PyObject *self,
@@ -544,44 +480,38 @@ static PyObject *pyxc_vbd_setextents(PyObject *self,
     u64             dom;
     unsigned int    vbd;
     xc_vbdextent_t *extents = NULL;
-    int             ret, i, nr_extents;
+    int             i, nr_extents;
 
     static char *kwd_list[] = { "dom", "vbd", "extents", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "LiO", kwd_list, 
                                       &dom, &vbd, &list) )
-    {
-        DPRINTF("could not parse parameter list.");
-        goto fail;
-    }
+        return NULL;
 
-    if ( (nr_extents = PyList_Size(list)) < 0 )
+    if ( !PyList_Check(list) )
     {
-        DPRINTF("parameter 'extents' is not a list.");
-        goto fail;
+        PyErr_SetString(PyExc_TypeError, "parameter 'extents' is not a list");
+        return NULL;
     }
 
-    if ( nr_extents != 0 )
+    if ( (nr_extents = PyList_Size(list)) != 0 )
     {
-        extents = malloc(nr_extents * sizeof(xc_vbdextent_t));
-        if ( extents == NULL )
-        {
-            DPRINTF("out of memory.");
-            goto fail;
-        }
+        if ( (extents = malloc(nr_extents * sizeof(xc_vbdextent_t))) == NULL )
+            return PyErr_NoMemory();
 
         for ( i = 0; i < nr_extents; i++ )
         {
             dict = PyList_GetItem(list, i);
             if ( !PyDict_Check(dict) )
             {
-                DPRINTF("extent %d -- extent is not a dictionary.", i);
+                PyErr_SetString(PyExc_TypeError, "extent is not a dictionary");
                 goto fail;
             }
 
             if ( (obj = PyDict_GetItemString(dict, "device")) == NULL )
             {
-                DPRINTF("extent %d -- 'device' is not in the dictionary.", i);
+                PyErr_SetString(PyExc_TypeError,
+                                "'device' is not in the dictionary");
                 goto fail;
             }
             if ( PyInt_Check(obj) )
@@ -594,14 +524,15 @@ static PyObject *pyxc_vbd_setextents(PyObject *self,
             }
             else
             {
-                DPRINTF("extent %d -- 'device' is not an int or long.", i);
+                PyErr_SetString(PyExc_TypeError,
+                                "'device' is not an int or long");
                 goto fail;
             }
 
             if ( (obj = PyDict_GetItemString(dict, "start_sector")) == NULL )
             {
-                DPRINTF("extent %d -- 'start_sector' is not "
-                        "in the dictionary.", i);
+                PyErr_SetString(PyExc_TypeError,
+                                "'start_sector' is not in the dictionary");
                 goto fail;
             }
             if ( PyInt_Check(obj) )
@@ -614,15 +545,15 @@ static PyObject *pyxc_vbd_setextents(PyObject *self,
             }
             else
             {
-                DPRINTF("extent %d -- 'start_sector' is not "
-                        "an int or long.", i);
+                PyErr_SetString(PyExc_TypeError,
+                                "'start_sector' is not an int or long");
                 goto fail;
             }
 
             if ( (obj = PyDict_GetItemString(dict, "nr_sectors")) == NULL )
             {
-                DPRINTF("extent %d -- 'nr_sectors' is not "
-                        "in the dictionary.", i);
+                PyErr_SetString(PyExc_TypeError,
+                                "'nr_sectors' is not in the dictionary");
                 goto fail;
             }
             if ( PyInt_Check(obj) )
@@ -635,19 +566,24 @@ static PyObject *pyxc_vbd_setextents(PyObject *self,
             }
             else
             {
-                DPRINTF("extent %d -- 'nr_sectors' is not "
-                        "an int or long.", i);
+                PyErr_SetString(PyExc_TypeError,
+                                "'nr_sectors' is not an int or long");
                 goto fail;
             }
         }
     }
 
-    ret = xc_vbd_setextents(xc->xc_handle, dom, vbd, nr_extents, extents);
-    
+    if ( xc_vbd_setextents(xc->xc_handle, dom, vbd, nr_extents, extents) != 0 )
+    {
+        PyErr_SetFromErrno(xc_error);
+        goto fail;
+    }
+
     if ( extents != NULL )
         free(extents);
     
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 
  fail:
     if ( extents != NULL )
@@ -666,51 +602,38 @@ static PyObject *pyxc_vbd_getextents(PyObject *self,
     u64             dom;
     unsigned int    vbd;
     xc_vbdextent_t *extents;
-    int             i, nr_extents, max_extents;
+    int             i, nr_extents;
 
     static char *kwd_list[] = { "dom", "vbd", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Li", kwd_list, 
                                       &dom, &vbd) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    extents = malloc(MAX_EXTENTS * sizeof(xc_vbdextent_t));
-    if ( extents == NULL )
-    {
-        DPRINTF("out of memory.");
-        max_extents = 0;
-    }
-    else
-    {
-        max_extents = MAX_EXTENTS;
-    }
+    if ( (extents = malloc(MAX_EXTENTS * sizeof(xc_vbdextent_t))) == NULL )
+        return PyErr_NoMemory();
 
-    nr_extents = xc_vbd_getextents(xc->xc_handle, dom, vbd, max_extents,
+    nr_extents = xc_vbd_getextents(xc->xc_handle, dom, vbd, MAX_EXTENTS,
                                    extents, NULL);
     
-    if ( nr_extents <= 0 )
+    if ( nr_extents < 0 )
     {
-        list = PyList_New(0);
+        free(extents);
+        return PyErr_SetFromErrno(xc_error);
     }
-    else
+
+    list = PyList_New(nr_extents);
+    for ( i = 0; i < nr_extents; i++ )
     {
-        list = PyList_New(nr_extents);
-        for ( i = 0; i < nr_extents; i++ )
-        {
-            PyList_SetItem(
-                list, i, 
-                Py_BuildValue("{s:i,s:L,s:L}",
-                              "device",       extents[i].real_device,
-                              "start_sector", extents[i].start_sector,
-                              "nr_sectors",   extents[i].nr_sectors));
-        }
+        PyList_SetItem(
+            list, i, 
+            Py_BuildValue("{s:i,s:L,s:L}",
+                          "device",       extents[i].real_device,
+                          "start_sector", extents[i].start_sector,
+                          "nr_sectors",   extents[i].nr_sectors));
     }
 
-    if ( extents != NULL )
-        free(extents);
+    free(extents);
     
     return list;
 }
@@ -731,20 +654,15 @@ static PyObject *pyxc_vbd_probe(PyObject *self,
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|Li", kwd_list, 
                                       &dom, &max_vbds) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    info = malloc(max_vbds * sizeof(xc_vbd_t));
-    if ( info == NULL )
-    {
-        DPRINTF("out of memory.");
-        nr_vbds = 0;
-    }
-    else
+    if ( (info = malloc(max_vbds * sizeof(xc_vbd_t))) == NULL )
+        return PyErr_NoMemory();
+
+    if ( (nr_vbds = xc_vbd_probe(xc->xc_handle, dom, max_vbds, info)) < 0 )
     {
-        nr_vbds = xc_vbd_probe(xc->xc_handle, dom, max_vbds, info);
+        free(info);
+        return PyErr_SetFromErrno(xc_error);
     }
 
     list = PyList_New(nr_vbds);
@@ -759,8 +677,7 @@ static PyObject *pyxc_vbd_probe(PyObject *self,
                           "nr_sectors", info[i].nr_sectors));
     }
 
-    if ( info != NULL )
-        free(info);
+    free(info);
 
     return list;
 }
@@ -770,30 +687,22 @@ static PyObject *pyxc_evtchn_open(PyObject *self,
                                   PyObject *kwds)
 {
     XcObject *xc = (XcObject *)self;
-    PyObject *dict;
 
     u64 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
-    int port1, port2, ret;
+    int port1, port2;
 
     static char *kwd_list[] = { "dom1", "dom2", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|LL", kwd_list, 
                                       &dom1, &dom2) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_evtchn_open(xc->xc_handle, dom1, dom2, &port1, &port2);
+    if ( xc_evtchn_open(xc->xc_handle, dom1, dom2, &port1, &port2) != 0 )
+        return PyErr_SetFromErrno(xc_error);
 
-    if ( ret < 0 )
-        dict = Py_BuildValue("{}");
-    else
-        dict = Py_BuildValue("{s:i,s:i}", 
-                             "port1", port1,
-                             "port2", port2);
-    
-    return dict;
+    return Py_BuildValue("{s:i,s:i}", 
+                         "port1", port1,
+                         "port2", port2);
 }
 
 static PyObject *pyxc_evtchn_close(PyObject *self,
@@ -803,20 +712,19 @@ static PyObject *pyxc_evtchn_close(PyObject *self,
     XcObject *xc = (XcObject *)self;
 
     u64 dom = DOMID_SELF;
-    int port, ret;
+    int port;
 
     static char *kwd_list[] = { "port", "dom", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|L", kwd_list, 
                                       &port, &dom) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_evtchn_close(xc->xc_handle, dom, port);
+    if ( xc_evtchn_close(xc->xc_handle, dom, port) != 0 )
+        return PyErr_SetFromErrno(xc_error);
 
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_evtchn_send(PyObject *self,
@@ -825,19 +733,18 @@ static PyObject *pyxc_evtchn_send(PyObject *self,
 {
     XcObject *xc = (XcObject *)self;
 
-    int port, ret;
+    int port;
 
     static char *kwd_list[] = { "port", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
-    ret = xc_evtchn_send(xc->xc_handle, port);
+    if ( xc_evtchn_send(xc->xc_handle, port) != 0 )
+        return PyErr_SetFromErrno(xc_error);
 
-    return PyInt_FromLong(ret);
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_evtchn_status(PyObject *self,
@@ -854,39 +761,31 @@ static PyObject *pyxc_evtchn_status(PyObject *self,
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|L", kwd_list, 
                                       &port1, &dom1) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
     ret = xc_evtchn_status(xc->xc_handle, dom1, port1, &dom2, &port2, &status);
+    if ( ret != 0 )
+        return PyErr_SetFromErrno(xc_error);
 
-    if ( ret < 0 )
+    switch ( status )
     {
+    case EVTCHNSTAT_closed:
+        dict = Py_BuildValue("{s:s}", 
+                             "status", "closed");
+        break;
+    case EVTCHNSTAT_disconnected:
+        dict = Py_BuildValue("{s:s}", 
+                             "status", "disconnected");
+        break;
+    case EVTCHNSTAT_connected:
+        dict = Py_BuildValue("{s:s,s:L,s:i}", 
+                             "status", "connected",
+                             "dom", dom2,
+                             "port", port2);
+        break;
+    default:
         dict = Py_BuildValue("{}");
-    }
-    else
-    {
-        switch ( status )
-        {
-        case EVTCHNSTAT_closed:
-            dict = Py_BuildValue("{s:s}", 
-                                 "status", "closed");
-            break;
-        case EVTCHNSTAT_disconnected:
-            dict = Py_BuildValue("{s:s}", 
-                                 "status", "disconnected");
-            break;
-        case EVTCHNSTAT_connected:
-            dict = Py_BuildValue("{s:s,s:L,s:i}", 
-                                 "status", "connected",
-                                 "dom", dom2,
-                                 "port", port2);
-            break;
-        default:
-            dict = Py_BuildValue("{}");
-            break;
-        }
+        break;
     }
     
     return dict;
@@ -904,15 +803,15 @@ static PyObject *pyxc_physdev_pci_access_modify(PyObject *self,
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Liiii", kwd_list, 
                                       &dom, &bus, &dev, &func, &enable) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
     ret = xc_physdev_pci_access_modify(
         xc->xc_handle, dom, bus, dev, func, enable);
-    
-    return PyInt_FromLong(ret);
+    if ( ret != 0 )
+        return PyErr_SetFromErrno(xc_error);
+
+    Py_INCREF(zero);
+    return zero;
 }
 
 static PyObject *pyxc_readconsolering(PyObject *self,
@@ -928,14 +827,13 @@ static PyObject *pyxc_readconsolering(PyObject *self,
     static char *kwd_list[] = { "clear", NULL };
 
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &clear) )
-    {
-        DPRINTF("could not parse parameter list.");
         return NULL;
-    }
 
     ret = xc_readconsolering(xc->xc_handle, str, sizeof(str), clear);
+    if ( ret < 0 )
+        return PyErr_SetFromErrno(xc_error);
 
-    return PyString_FromStringAndSize(str, (ret < 0) ? 0 : ret);
+    return PyString_FromStringAndSize(str, ret);
 }
 
 static PyObject *pyxc_physinfo(PyObject *self,
@@ -943,26 +841,20 @@ static PyObject *pyxc_physinfo(PyObject *self,
                               PyObject *kwds)
 {
     XcObject *xc = (XcObject *)self;
-    PyObject *ret_obj;
-    int xc_ret;
     xc_physinfo_t info;
     
-    if ( (xc_ret = xc_physinfo(xc->xc_handle, &info)) == 0 )
-    {
-        ret_obj = Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}",
-                                "ht_per_core", info.ht_per_core,
-                                "cores",       info.cores,
-                                "total_pages", info.total_pages,
-                                "free_pages",  info.free_pages,
-                                "cpu_khz",     info.cpu_khz);
-    }
-    else
-    {
-        Py_INCREF(Py_None);
-        ret_obj = Py_None;
-    }
-    
-    return ret_obj;
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    if ( xc_physinfo(xc->xc_handle, &info) != 0 )
+        return PyErr_SetFromErrno(xc_error);
+
+    return Py_BuildValue("{s:i,s:i,s:l,s:l,s:l}",
+                         "ht_per_core", info.ht_per_core,
+                         "cores",       info.cores,
+                         "total_pages", info.total_pages,
+                         "free_pages",  info.free_pages,
+                         "cpu_khz",     info.cpu_khz);
 }
 
 static PyMethodDef pyxc_methods[] = {
@@ -1305,7 +1197,15 @@ static PyMethodDef PyXc_methods[] = {
     { NULL, NULL, 0, NULL }
 };
 
-DL_EXPORT(void) initXc(void)
+PyMODINIT_FUNC initXc(void)
 {
-    Py_InitModule("Xc", PyXc_methods);
+    PyObject *m, *d;
+
+    m = Py_InitModule("Xc", PyXc_methods);
+
+    d = PyModule_GetDict(m);
+    xc_error = PyErr_NewException("Xc.error", NULL, NULL);
+    PyDict_SetItemString(d, "error", xc_error);
+
+    zero = PyInt_FromLong(0);
 }
index 27b6fbb3904e94b8b0d5c2abdc9928c95d8915d0..520f5850629e5356b3629b652f445d26c7b1c06b 100644 (file)
@@ -1,4 +1,4 @@
-import string, re, os, sys
+import os, re, socket, string, sys, tempfile
 
 ##### Module variables
 
@@ -184,6 +184,27 @@ def lookup_disk_uname( uname ):
     return segments
 
 
+##### Management of the Xen control daemon
+##### (c) Keir Fraser, University of Cambridge
+
+def xend_control_message( message ):
+    """Takes a textual control message and sends it to the 'xend' Xen
+    control daemon. Returns a dictionary containing the daemon's multi-part
+    response."""
+    tmpdir = tempfile.mkdtemp()
+    try:
+        ctl = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+        ctl.bind(tmpdir+'/sock')
+        ctl.sendto(message, '/var/run/xend/management_sock')
+        data, addr = ctl.recvfrom(2048)
+        ctl.close()
+    finally:
+        if os.path.exists(tmpdir+'/sock'):
+            os.unlink(tmpdir+'/sock')
+        if os.path.exists(tmpdir):
+            os.rmdir(tmpdir)    
+    return eval(data)
+
 
 ##### VD Management-related functions
 
index 619f98097528cb2afcbfec14b2bd12efe0660d26..de6aeb39828d3bd185699d467861fe81fcd4fa53 100644 (file)
@@ -1,27 +1,24 @@
 
-CC       = gcc
-CFLAGS   = -Wall -O3 
-CFLAGS  += -I../xc/lib -I../../xenolinux-sparse/include
-
-HDRS     = $(wildcard *.h)
-OBJS     = $(patsubst %.c,%.o,$(wildcard *.c))
-
-BIN      = xend
-
-all: $(BIN)
+all:
+       python setup.py build
 
 install: all
-       mkdir -p $(prefix)/usr/sbin
-       cp $(BIN) $(prefix)/usr/sbin
-       chmod 755 $(prefix)/usr/sbin/$(BIN)
+       if [ "$(prefix)" = "" ]; then python setup.py install; \
+       else python setup.py install --root "$(prefix)"; fi
+       install --mode=755 xend.py $(prefix)/usr/sbin
+       ln -sf xend.py $(prefix)/usr/sbin/xend
 
 dist: all
-       mkdir -p ../../../install/sbin
-       cp $(BIN) ../../../install/sbin
-       chmod 755 ../../../install/sbin/$(BIN)
+       mkdir -p ../../../../install/lib/python
+       for i in `find . -name 'xend_utils.so'` ; do           \
+               install --mode=755 $$i ../../../../install/lib/python/`basename $$i` ; \
+       done
+       python -c 'import py_compile, sys; py_compile.compile("XenoUtil.py")'
+       install --mode=755 xend.py ../../../../install/sbin
+       ln -sf xend.py ../../../../install/sbin/xend
 
 clean:
-       $(RM) *.a *.so *.o *.rpm $(BIN)
+       rm -rf build *.pyc *.pyo *.a *.so *.o *~ *.rpm 
 
 $(BIN): $(OBJS)
        $(CC) -o $@ $^ -L../xc/lib -lxc
diff --git a/tools/xend/setup.py b/tools/xend/setup.py
new file mode 100644 (file)
index 0000000..9bc9677
--- /dev/null
@@ -0,0 +1,11 @@
+
+from distutils.core import setup, Extension
+
+module = Extension("xend_utils",
+                   include_dirs         = ["../xc/lib",
+                                           "../../xenolinux-sparse/include"],
+                   library_dirs         = ["../xc/lib"],
+                   libraries            = ["xc"],
+                   sources              = ["xend_utils.c"])
+
+setup(name = "xend_utils", version = "1.0", ext_modules = [module])
diff --git a/tools/xend/xend.py b/tools/xend/xend.py
new file mode 100755 (executable)
index 0000000..313dc06
--- /dev/null
@@ -0,0 +1,454 @@
+#!/usr/bin/env python
+
+
+###########################################################
+## xend.py -- Xen controller daemon
+## Copyright (c) 2004, K A Fraser (University of Cambridge)
+###########################################################
+
+
+import errno, re, os, pwd, select, signal, socket, struct, sys, tempfile, time
+import xend_utils, Xc
+
+
+
+# The following parameters could be placed in a configuration file.
+PID  = '/var/run/xend.pid'
+LOG  = '/var/log/xend.log'
+USER = 'root'
+CONTROL_DIR  = '/var/run/xend'
+UNIX_SOCK    = 'management_sock' # relative to CONTROL_DIR
+
+
+
+##
+## console_interface:
+##  Each control interface owns an instance of this class, which manages
+##  the current state of the console interface. Normally a console interface
+##  will be one of two state:
+##   LISTENING: listening for a connection on TCP port 'self.port'
+##   CONNECTED: sending/receiving console data on TCP port 'self.port'
+##
+##  A dictionary of all active interfaces, indexed by TCP socket descriptor,
+##  is accessible as 'console_interface.interface_list'.
+##
+##  NB. When a class instance is to be destroyed you *must* call the 'close'
+##  method. Otherwise a stale reference will eb left in the interface list.
+##
+class console_interface:
+
+    # The various states that a console interface may be in.
+    CLOSED    = 0 # No console activity
+    LISTENING = 1 # Listening on port 'self.port'. Socket object 'self.sock'.
+    CONNECTED = 2 # Active connection on 'self.port'. Socket obj 'self.sock'.
+
+
+    # Dictionary of all active (non-closed) console interfaces.
+    interface_list = {}
+
+
+    # NB. 'key' is an opaque value that has no meaning in this class.
+    def __init__(self, port, key):
+        self.status = console_interface.CLOSED
+        self.port   = port
+        self.key    = key
+
+
+    # Is this interface closed (inactive)?
+    def closed(self):
+        return self.status == console_interface.CLOSED
+
+
+    # Is this interface listening?
+    def listening(self):
+        return self.status == console_interface.LISTENING
+
+
+    # Is this interface active and connected?
+    def connected(self):
+        return self.status == console_interface.CONNECTED
+
+
+    # Close the interface, if it is not closed already.
+    def close(self):
+        if not self.closed():
+            del console_interface.interface_list[self.sock.fileno()]
+            self.sock.close()
+            del self.sock
+            self.status = console_interface.CLOSED
+
+
+    # Move the interface into the 'listening' state. Opens a new listening
+    # socket and updates 'interface_list'.
+    def listen(self):
+        # Close old socket (if any), and create a fresh one.
+        self.close()
+        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+
+        try:
+            # Turn the new socket into a non-blocking listener.
+            self.sock.setblocking(False)
+            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
+                                 struct.pack('ii', 0, 0))
+            self.sock.bind(('', self.port))
+            self.sock.listen(1)
+
+            # Announce the new status of thsi interface.
+            self.status = console_interface.LISTENING
+            console_interface.interface_list[self.sock.fileno()] = self
+
+        except:
+            # In case of trouble ensure we get rid of dangling socket reference
+            self.sock.close()
+            del self.sock
+            raise
+
+
+    # Move a listening interface into the 'connected' state.
+    def connect(self):
+        # Pick up a new connection, if one is available.
+        try:
+            (sock, addr) = self.sock.accept()
+        except:
+            return 0
+        sock.setblocking(False)
+        sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
+                        struct.pack('ii', 0, 0))
+
+        # Close the listening socket.
+        self.sock.close()
+
+        # Publish the new socket and the new interface state.
+        self.sock = sock
+        self.status = console_interface.CONNECTED
+        console_interface.interface_list[self.sock.fileno()] = self
+        return 1
+
+
+
+##
+## new_control_interface:
+##  Create a new control interface with the specified domain 'dom'.
+##  The console port may also be specified; otehrwise a suitable port is
+##  automatically allocated.
+##
+def new_control_interface(dom, console_port=-1):
+    # Allocate an event channel. Clear pending notifications.
+    port = xend_utils.port(dom)
+    notifier.clear(port.local_port, notifier.NORMAL)
+    notifier.clear(port.local_port, notifier.DISCONNECT)
+    
+    # If necessary, compute a suitable TCP port for console I/O.
+    if console_port < 0:
+        console_port = 9600 + port.local_port
+
+    # Create a listenign console interface.
+    con_if = console_interface(console_port, port.local_port)
+    con_if.listen()
+
+    # Add control state to the master list.
+    control_list[port.local_port] = \
+      (port, xend_utils.buffer(), xend_utils.buffer(), con_if)
+
+    # Construct the successful response to be returned to the requester.
+    response = { 'success': True }
+    response['local_port']   = port.local_port
+    response['remote_port']  = port.remote_port
+    response['console_port'] = console_port
+    return response
+
+
+        
+def daemon_loop():
+    global control_list, notifier
+
+    xc = Xc.new()
+    control_list = {}
+
+    # Ignore writes to disconnected sockets. We clean up differently.
+    signal.signal(signal.SIGPIPE, signal.SIG_IGN)
+
+    # Construct the management interface. This is a UNIX domain socket via
+    # which we receive 'request' datagrams. Each request is a string that
+    # can be eval'ed as a Python statement. Responses can be remotely eval'ed
+    # by the requester to create a Python dictionary of result values.
+    management_interface = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
+    if os.path.exists(CONTROL_DIR+'/'+UNIX_SOCK):
+        os.unlink(CONTROL_DIR+'/'+UNIX_SOCK)
+    management_interface.setblocking(False)
+    management_interface.bind(CONTROL_DIR+'/'+UNIX_SOCK)
+
+    notifier = xend_utils.notifier()
+
+    ##
+    ## MAIN LOOP
+    ## 
+    while 1:
+
+        # Construct a poll set. We wait on:
+        #  1. Requests on the management interface.
+        #  2. Incoming event-channel notifications.
+        # Furthermore, for each active control interface:
+        #  3. Incoming console data.
+        #  4. Space for outgoing console data (if there is data to send).
+        waitset = select.poll()
+        waitset.register(management_interface, select.POLLIN)
+        waitset.register(notifier, select.POLLIN)
+        for idx, (port, rbuf, wbuf, con_if) in control_list.items():
+            if not con_if.closed():
+                pflags = select.POLLIN
+                if not rbuf.empty() and con_if.connected():
+                    pflags = select.POLLIN | select.POLLOUT
+                waitset.register(con_if.sock.fileno(), pflags)
+
+        # Wait for something to do...
+        fdset = waitset.poll()
+        
+        # Look for messages on the management interface.
+        # These should consist of executable Python statements that call
+        # well-known management functions (e.g., new_control_interface(dom=9)).
+        try:
+            data, addr = management_interface.recvfrom(2048)
+        except socket.error, error:
+            if error[0] != errno.EAGAIN:
+                raise
+        else:
+            if addr:
+                # Evaluate the request in an exception-trapping sandbox.
+                try:
+                    print "Mgmt_req[%s]: %s" % (addr, data)
+                    response = str(eval(data))
+
+                except:
+                    # Catch all exceptions and turn into an error response:
+                    #  status:          False
+                    #  error_type:      'exception'
+                    #  exception_type:  name of exception type.
+                    #  exception value: textual exception value.
+                    exc_type, exc_val = sys.exc_info()[:2]
+                    response = { 'success': False }
+                    response['error_type'] = 'exception'
+                    response['exception_type'] = str(exc_type)
+                    response['exception_value'] = str(exc_val)
+                    response = str(response)
+
+                # Try to send a response to the requester.
+                try:
+                    print "Mgmt_rsp[%s]: %s" % (addr, response)
+                    management_interface.sendto(response, addr)
+                except socket.error, error:
+                    pass
+                
+        # Do work for every console interface that hit in the poll set.
+        for (fd, events) in fdset:
+            if not console_interface.interface_list.has_key(fd):
+                continue
+            con_if = console_interface.interface_list[fd]
+
+            # If the interface is listening, check for pending connections.
+            if con_if.listening():
+                con_if.connect()
+
+            # All done if the interface is not connected.
+            if not con_if.connected():
+                continue
+            (port, rbuf, wbuf, con_if) = control_list[con_if.key]
+
+            # Send as much pending data as possible via the socket.
+            while not rbuf.empty():
+                try:
+                    bytes = con_if.sock.send(rbuf.peek())
+                    if bytes > 0:
+                        rbuf.discard(bytes)
+                except socket.error, error:
+                    pass
+
+            # Read as much data as is available. Don't worry about
+            # overflowing our buffer: it's more important to read the
+            # incoming data stream and detect errors or closure of the
+            # remote end in a timely manner.
+            try:
+                while 1:
+                    data = con_if.sock.recv(2048)
+                    # Return of zero means the remote end has disconnected.
+                    # We therefore return the console interface to listening.
+                    if not data:
+                        con_if.listen()
+                        break
+                    wbuf.write(data)
+            except socket.error, error:
+                # Assume that most errors mean that the connection is dead.
+                # In such cases we return the interface to 'listening' state.
+                if error[0] != errno.EAGAIN:
+                    print "Better return to listening"
+                    con_if.listen()
+                    print "New status: " + str(con_if.status)
+
+            # We may now have pending data to send via the relevant
+            # inter-domain control interface. If so then we send all we can
+            # and notify the remote end.
+            work_done = False
+            while not wbuf.empty() and port.space_to_write_request():
+                msg = xend_utils.message(0, 0, 0)
+                msg.append_payload(wbuf.read(msg.MAX_PAYLOAD))
+                port.write_request(msg)
+                work_done = True
+            if work_done:
+                port.notify()
+
+        # Process control-interface notifications from other guest OSes.
+        while 1:            
+            # Grab a notification, if there is one.
+            notification = notifier.read()
+            if not notification:
+                break
+            (idx, type) = notification
+
+            # If we pick up a disconnect notification then we do any necessary
+            # cleanup, even if the event channel doesn't belong to us.
+            # This is intended to prevent the event-channel port space from
+            # getting clogged with stale connections.
+            if type == notifier.DISCONNECT:
+                ret = xc.evtchn_status(idx)
+                if ret['status'] != 'connected':
+                    notifier.clear(idx, notifier.NORMAL)
+                    notifier.clear(idx, notifier.DISCONNECT)
+                    if control_list.has_key(idx):
+                        (port, rbuf, wbuf, con_if) =  control_list[idx]
+                        con_if.close()
+                        del control_list[idx], port, rbuf, wbuf, con_if
+                    elif ret['status'] == 'disconnected':
+                        # There's noone to do the closure for us...
+                        xc.evtchn_close(idx)
+
+            # A standard notification: probably means there are messages to
+            # read or that there is space to write messages.
+            elif type == notifier.NORMAL and control_list.has_key(idx):
+                (port, rbuf, wbuf, con_if) = control_list[idx]
+                work_done = False
+
+                # We clear the notification before doing any work, to avoid
+                # races.
+                notifier.clear(idx, notifier.NORMAL)
+
+                # Read incoming requests. Currently assume that request
+                # message always containb console data.
+                while port.request_to_read():
+                    msg = port.read_request()
+                    rbuf.write(msg.get_payload())
+                    port.write_response(msg)
+                    work_done = True
+
+                # Incoming responses are currently thrown on the floor.
+                while port.response_to_read():
+                    msg = port.read_response()
+                    work_done = True
+
+                # Send as much pending console data as there is room for.
+                while not wbuf.empty() and port.space_to_write_request():
+                    msg = xend_utils.message(0, 0, 0)
+                    msg.append_payload(wbuf.read(msg.MAX_PAYLOAD))
+                    port.write_request(msg)
+                    work_done = True
+
+                # Finally, notify the remote end of any work that we did.
+                if work_done:
+                    port.notify()
+
+
+
+def cleanup_daemon(kill=False):
+    # No cleanup to do if the PID file is empty.
+    if not os.path.isfile(PID) or not os.path.getsize(PID):
+        return 0
+    # Read the PID of the previous invocation and search active process list.
+    pid = open(PID, 'r').read()
+    lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines()
+    for line in lines:
+        if re.search('^ *' + pid + '.+xend', line):
+            if not kill:
+                print "Daemon is already running (PID %d)" % int(pid)
+                return 1
+            # Old daemon is still active: terminate it.
+            os.kill(int(pid), 1)
+    # Delete the, now stale, PID file.
+    os.remove(PID)
+    return 0
+
+
+
+def start_daemon():
+    if cleanup_daemon(kill=False):
+        return 1
+
+    if not os.path.exists(CONTROL_DIR):
+        os.mkdir(CONTROL_DIR)
+
+    # Open log file. Truncate it if non-empty, and request line buffering.
+    if os.path.isfile(LOG):
+        os.rename(LOG, LOG+'.old')
+    logfile = open(LOG, 'w+', 1)
+
+    # Detach from TTY.
+    os.setsid()
+
+    # Set the UID.
+    try:
+        os.setuid(pwd.getpwnam(USER)[2])
+    except KeyError, error:
+        print "Error: no such user '%s'" % USER
+        return 1
+
+    # Ensure that zombie children are automatically reaped.
+    xend_utils.autoreap()
+
+    # Fork -- parent writes the PID file and exits.
+    pid = os.fork()
+    if pid:
+        pidfile = open(PID, 'w')
+        pidfile.write(str(pid))
+        pidfile.close()
+        return 0
+
+    # Close down standard file handles
+    try:
+        os.close(0) # stdin
+        os.close(1) # stdout
+        os.close(2) # stderr
+    except:
+        pass
+
+    # Redirect output to log file, then enter the main loop.
+    sys.stdout = sys.stderr = logfile
+    daemon_loop()
+    return 0
+
+
+
+def stop_daemon():
+    return cleanup_daemon(kill=True)
+
+
+
+def main():
+    xend_utils.autoreap()
+    if not sys.argv[1:]:
+        print 'usage: %s {start|stop|restart}' % sys.argv[0]
+    elif os.fork():
+        pid, status = os.wait()
+        return status >> 8
+    elif sys.argv[1] == 'start':
+        return start_daemon()
+    elif sys.argv[1] == 'stop':
+        return stop_daemon()
+    elif sys.argv[1] == 'restart':
+        return stop_daemon() or start_daemon()
+    else:
+        print 'not an option:', sys.argv[1]
+    return 1
+
+
+
+if __name__ == '__main__':
+    sys.exit(main())
index ef6e903ddd532933895703d99762ccebc3f29000..81b101e5c82ea136d5c0495b8c94bad45dbd599f 100644 (file)
@@ -1,16 +1,16 @@
 /******************************************************************************
- * xend.c
- * 
- * The grand Xen daemon. For now it's just a virtual-console concentrator.
+ * xend_utils.c
  * 
  * Copyright (c) 2004, K A Fraser
  */
 
+#include <Python.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/mman.h>
 #define PORTIDX_MASK    0x7fff   /* Strip subtype to obtain port index. */
 #define EVTCHN_RESET _IO('E', 1) /* Clear notification buffer. Clear errors. */
 
-/* Error macros. */
-#define ERROR(_f, _a...)     \
-    fprintf ( stderr, "ERROR: " _f "\n" , ## _a );
-#define SYS_ERROR(_f, _a...) \
-    fprintf ( stderr, "ERROR: " _f " [errno=%d (%s)]\n" , \
-              ## _a , errno , strerror(errno) );
-#define HINT(_f, _a...)      \
-    fprintf ( stderr, "Hint: " _f "\n" , ## _a );
-#define ROOT_HINT() HINT("You must execute this daemon as root.")
-#define DOM0_HINT() HINT("You must execute this daemon " \
-                         "on a privileged Xenolinux instance (e.g., DOM0).")
-
-#if 0
-#define DPRINTF(_f, _a...)  \
-    fprintf ( stdout, _f "\n" , ## _a );
-#else
-#define DPRINTF(_f, _a...) ((void)0)
-#endif
-
-/* Per-port Tx/Rx buffering. */
-#define CONBUFSZ 65536
-#define MASK_CONBUF_IDX(_i) ((_i)&(CONBUFSZ-1))
-
-struct portinfo;
-typedef struct portinfo {
-    u64              dom;
-    control_if_t    *interface;
-    CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
-    CONTROL_RING_IDX rx_req_prod, rx_resp_cons;
-    char            *tx_buf, *rx_buf;
-    unsigned int     txp, txc, rxp, rxc;
-#define CONSTAT_CLOSED    0
-#define CONSTAT_LISTENING 1
-#define CONSTAT_CONNECTED 2
-    int              con_fd, con_status;
-    struct portinfo **pprev, *next; /* links to other active ports */
-} portinfo_t;
-
-#define PORT(_pinfo) ((_pinfo)-portinfo)
-#define TX_EMPTY(_pinfo) ((_pinfo)->txp == (_pinfo)->txc)
-#define TX_FULL(_pinfo)  (((_pinfo)->txp - (_pinfo)->txc) == CONBUFSZ)
-#define RX_EMPTY(_pinfo) ((_pinfo)->rxp == (_pinfo)->rxc)
-#define RX_FULL(_pinfo)  (((_pinfo)->rxp - (_pinfo)->rxc) == CONBUFSZ)
-
-static portinfo_t *active_head;   /* linked list of active ports */
-static portinfo_t portinfo[1024]; /* array of all ports */    
-static int xc_fd, evt_fd, mem_fd;
-
-#define PAGE_SIZE           4096 /* size of a machine page frame            */
-#define BATCH_SIZE           512 /* maximum notifications to read at a time */
-
-static int make_consock_listener(portinfo_t *pinfo);
-static int make_consock_connected(portinfo_t *pinfo);
-static void make_consock_closed(portinfo_t *pinfo);
-static void do_consock_read(portinfo_t *pinfo);
-static void do_consock_write(portinfo_t *pinfo);
-static int process_evtchn_reads(portinfo_t *pinfo);
-static int process_evtchn_writes(portinfo_t *pinfo);
+/* Size of a machine page frame. */
+#define PAGE_SIZE 4096
+
+
+/*
+ * *********************** NOTIFIER ***********************
+ */
+
+typedef struct {
+    PyObject_HEAD;
+    int evtchn_fd;
+} xu_notifier_object;
+
+static PyObject *xu_notifier_read(PyObject *self, PyObject *args)
+{
+    xu_notifier_object *xun = (xu_notifier_object *)self;
+    u16 v;
+    int bytes;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+    
+    while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 )
+    {
+        if ( errno == EINTR )
+            continue;
+        if ( errno == EAGAIN )
+            goto none;
+        return PyErr_SetFromErrno(PyExc_IOError);
+    }
+    
+    if ( bytes == sizeof(v) )
+        return Py_BuildValue("(i,i)", v&PORTIDX_MASK, v&~PORTIDX_MASK);
+
+ none:
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *xu_notifier_clear(PyObject *self, PyObject *args)
+{
+    xu_notifier_object *xun = (xu_notifier_object *)self;
+    u16 v;
+    int idx, type;
+
+    if ( !PyArg_ParseTuple(args, "ii", &idx, &type) )
+        return NULL;
+    
+    v = (u16)idx | (u16)type;
+
+    (void)write(xun->evtchn_fd, &v, sizeof(v));
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
+{
+    xu_notifier_object *xun = (xu_notifier_object *)self;
+    return PyInt_FromLong(xun->evtchn_fd);
+}
+
+static PyMethodDef xu_notifier_methods[] = {
+    { "read",
+      (PyCFunction)xu_notifier_read,
+      METH_VARARGS,
+      "Read a (@port, @type) pair.\n" },
+
+    { "clear", 
+      (PyCFunction)xu_notifier_clear,
+      METH_VARARGS,
+      "Clear a (@port, @type) pair.\n" },
+
+    { "fileno", 
+      (PyCFunction)xu_notifier_fileno,
+      METH_VARARGS,
+      "Return the file descriptor for the notification channel.\n" },
+
+    { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_notifier_type;
+
+static PyObject *xu_notifier_new(PyObject *self, PyObject *args)
+{
+    xu_notifier_object *xun;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    xun = PyObject_New(xu_notifier_object, &xu_notifier_type);
+
+    xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
+    if ( xun->evtchn_fd == -1 )
+    {
+        PyObject_Del((PyObject *)xun);
+        return PyErr_SetFromErrno(PyExc_IOError);
+    }
+
+    return (PyObject *)xun;
+}
+
+static PyObject *xu_notifier_getattr(PyObject *obj, char *name)
+{
+    if ( strcmp(name, "DISCONNECT") == 0 )
+        return PyInt_FromLong(PORT_DISCONNECT);
+    if ( strcmp(name, "NORMAL") == 0 )
+        return PyInt_FromLong(PORT_NORMAL);
+    return Py_FindMethod(xu_notifier_methods, obj, name);
+}
+
+static void xu_notifier_dealloc(PyObject *self)
+{
+    xu_notifier_object *xun = (xu_notifier_object *)self;
+    (void)close(xun->evtchn_fd);
+    PyObject_Del(self);
+}
+
+static PyTypeObject xu_notifier_type = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,
+    "notifier",
+    sizeof(xu_notifier_object),
+    0,
+    xu_notifier_dealloc, /* tp_dealloc     */
+    NULL,                /* tp_print       */
+    xu_notifier_getattr, /* tp_getattr     */
+    NULL,                /* tp_setattr     */
+    NULL,                /* tp_compare     */
+    NULL,                /* tp_repr        */
+    NULL,                /* tp_as_number   */
+    NULL,                /* tp_as_sequence */
+    NULL,                /* tp_as_mapping  */
+    NULL                 /* tp_hash        */
+};
+
+
+
+/*
+ * *********************** MESSAGE ***********************
+ */
+
+typedef struct {
+    PyObject_HEAD;
+    control_msg_t msg;
+} xu_message_object;
+
+static PyObject *xu_message_append_payload(PyObject *self, PyObject *args)
+{
+    xu_message_object *xum = (xu_message_object *)self;
+    char *str;
+    int len;
+
+    if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
+        return NULL;
+
+    if ( (len + xum->msg.length) > sizeof(xum->msg.msg) )
+    {
+        PyErr_SetString(PyExc_RuntimeError, "out of space in control message");
+        return NULL;
+    }
+
+    memcpy(&xum->msg.msg[xum->msg.length], str, len);
+    xum->msg.length += len;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *xu_message_get_payload(PyObject *self, PyObject *args)
+{
+    xu_message_object *xum = (xu_message_object *)self;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    return PyString_FromStringAndSize(xum->msg.msg, xum->msg.length);
+}
+
+static PyObject *xu_message_set_header(PyObject *self, 
+                                       PyObject *args, 
+                                       PyObject *kwds)
+{
+    xu_message_object *xum = (xu_message_object *)self;
+    int type = -1, subtype = -1, id = -1;
+
+    static char *kwd_list[] = { "type", "subtype", "id", NULL };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iii", kwd_list,
+                                      &type, &subtype, &id) )
+        return NULL;
+
+    if ( type != -1 )
+        xum->msg.type = (u8)type;
+    if ( subtype != -1 )
+        xum->msg.subtype = (u8)subtype;
+    if ( id != -1 )
+        xum->msg.id = (u8)id;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *xu_message_get_header(PyObject *self, PyObject *args)
+{
+    xu_message_object *xum = (xu_message_object *)self;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    return Py_BuildValue("{s:i,s:i,s:i}",
+                         "type",    xum->msg.type,
+                         "subtype", xum->msg.subtype,
+                         "id",      xum->msg.id);
+}
+
+static PyMethodDef xu_message_methods[] = {
+    { "append_payload", 
+      (PyCFunction)xu_message_append_payload,
+      METH_VARARGS,
+      "Append @str to the message payload.\n" },
+
+    { "get_payload",
+      (PyCFunction)xu_message_get_payload,
+      METH_VARARGS,
+      "Return the message payload in string form.\n" },
+
+    { "set_header",
+      (PyCFunction)xu_message_set_header,
+      METH_VARARGS | METH_KEYWORDS,
+      "Accepts keywords @type, @subtype, and @id.\n" },
+
+    { "get_header",
+      (PyCFunction)xu_message_get_header,
+      METH_VARARGS,
+      "Returns a dictionary of values for @type, @subtype, and @id.\n" },
+
+    { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_message_type;
+
+static PyObject *xu_message_new(PyObject *self, PyObject *args)
+{
+    xu_message_object *xum;
+    int type, subtype, id;
+
+    if ( !PyArg_ParseTuple(args, "iii", &type, &subtype, &id) )
+        return NULL;
+
+    xum = PyObject_New(xu_message_object, &xu_message_type);
+
+    xum->msg.type    = type;
+    xum->msg.subtype = subtype;
+    xum->msg.id      = id;
+    xum->msg.length  = 0;
+
+    return (PyObject *)xum;
+}
+
+static PyObject *xu_message_getattr(PyObject *obj, char *name)
+{
+    xu_message_object *xum;
+    if ( strcmp(name, "MAX_PAYLOAD") == 0 )
+        return PyInt_FromLong(sizeof(xum->msg.msg));
+    return Py_FindMethod(xu_message_methods, obj, name);
+}
+
+static void xu_message_dealloc(PyObject *self)
+{
+    PyObject_Del(self);
+}
+
+static PyTypeObject xu_message_type = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,
+    "message",
+    sizeof(xu_message_object),
+    0,
+    xu_message_dealloc,   /* tp_dealloc     */
+    NULL,                /* tp_print       */
+    xu_message_getattr,   /* tp_getattr     */
+    NULL,                /* tp_setattr     */
+    NULL,                /* tp_compare     */
+    NULL,                /* tp_repr        */
+    NULL,                /* tp_as_number   */
+    NULL,                /* tp_as_sequence */
+    NULL,                /* tp_as_mapping  */
+    NULL                 /* tp_hash        */
+};
+
+
+
+/*
+ * *********************** PORT ***********************
+ */
 
 static control_if_t *map_control_interface(int fd, unsigned long pfn)
 {
@@ -99,518 +337,670 @@ static control_if_t *map_control_interface(int fd, unsigned long pfn)
         return NULL;
     return (control_if_t *)(vaddr + 2048);
 }
-
 static void unmap_control_interface(int fd, control_if_t *c)
 {
     char *vaddr = (char *)c - 2048;
     (void)munmap(vaddr, PAGE_SIZE);
 }
 
-/* Returns TRUE if the channel is open on exit. */
-static int handle_channel_exception(unsigned int port)
+typedef struct {
+    PyObject_HEAD;
+    int mem_fd;
+    int xc_handle;
+    u64 remote_dom;
+    int local_port, remote_port;
+    control_if_t    *interface;
+    CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
+    CONTROL_RING_IDX rx_req_prod, rx_resp_cons;
+} xu_port_object;
+
+static PyObject *port_error;
+
+static PyObject *xu_port_notify(PyObject *self, PyObject *args)
 {
-    xc_dominfo_t info;
-    unsigned int remote_port, status;
-    u64          remote_dom;
-    u16          wbuf;
-    portinfo_t  *pinfo = &portinfo[port];
+    xu_port_object *xup = (xu_port_object *)self;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    (void)xc_evtchn_send(xup->xc_handle, xup->local_port);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *xu_port_read_request(PyObject *self, PyObject *args)
+{
+    xu_port_object    *xup = (xu_port_object *)self;
+    xu_message_object *xum;
+    CONTROL_RING_IDX   c = xup->tx_req_cons;
+    control_if_t      *cif = xup->interface;
+    control_msg_t     *cmsg;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
 
-    if ( xc_evtchn_status(xc_fd, DOMID_SELF, port, 
-                          &remote_dom, &remote_port, &status) != 0 )
+    if ( (c == cif->tx_req_prod) || 
+         ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
     {
-        SYS_ERROR("Unexpected failure when obtaining port-%d status.", port);
-        exit(1);
+        PyErr_SetString(port_error, "no request to read");
+        return NULL;
     }
-    
-    if ( status != EVTCHNSTAT_connected )
+
+    cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)];
+    xum = PyObject_New(xu_message_object, &xu_message_type);
+    memcpy(&xum->msg, cmsg, sizeof(*cmsg));
+    if ( xum->msg.length > sizeof(xum->msg.msg) )
+        xum->msg.length = sizeof(xum->msg.msg);
+    xup->tx_req_cons++;
+    return (PyObject *)xum;
+}
+
+static PyObject *xu_port_write_request(PyObject *self, PyObject *args)
+{
+    xu_port_object    *xup = (xu_port_object *)self;
+    xu_message_object *xum;
+    CONTROL_RING_IDX   p = xup->rx_req_prod;
+    control_if_t      *cif = xup->interface;
+    control_msg_t     *cmsg;
+
+    if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
+        return NULL;
+
+    if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
     {
-        DPRINTF("Port %d not connected: cleaning up.", port);
-        if ( pinfo->interface != NULL )
-        {
-            unmap_control_interface(mem_fd, pinfo->interface);
-            pinfo->interface = NULL;
-            *(pinfo->pprev) = pinfo->next;
-            if ( pinfo->next != NULL )
-                pinfo->next->pprev = pinfo->pprev;
-            make_consock_closed(pinfo);
-            free(pinfo->tx_buf);
-            free(pinfo->rx_buf);
-            memset(pinfo, 0, sizeof(*pinfo));
-        }
-        /* Cleanup sanity: we'll be the grim reaper. */
-        wbuf = port | PORT_NORMAL;
-        (void)write(evt_fd, &wbuf, sizeof(wbuf));
-        wbuf = port | PORT_DISCONNECT;
-        (void)write(evt_fd, &wbuf, sizeof(wbuf));
-        if ( status == EVTCHNSTAT_disconnected )
-            (void)xc_evtchn_close(xc_fd, DOMID_SELF, port);
-        return 0;
+        PyErr_SetString(PyExc_TypeError, "expected a xend_utils.message");
+        return NULL;        
     }
 
-    /* We only deal with initial ports (id == 0). */
-    if ( remote_port != 0 )
-        return 0;
-
-    if ( pinfo->interface == NULL )
+    if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
     {
-        DPRINTF("New control interface for DOM%llu on port %d.", 
-                remote_dom, port);
-        if ( xc_domain_getinfo(xc_fd, remote_dom, 1, &info) != 1 )
-        {
-            SYS_ERROR("Failed to obtain DOM%llu status.", remote_dom);
-            exit(1);
-        }
-        memset(pinfo, 0, sizeof(*pinfo));
-        pinfo->interface = 
-            map_control_interface(mem_fd, info.shared_info_frame);
-        pinfo->tx_buf = malloc(CONBUFSZ);
-        pinfo->rx_buf = malloc(CONBUFSZ);
-        pinfo->dom = remote_dom;
-        pinfo->con_status = CONSTAT_CLOSED;
-        if ( !make_consock_listener(pinfo) )
-        {
-            ERROR("Could not start console %d in listener status.",
-                  PORT(pinfo));
-            exit(1);
-        }
-        pinfo->pprev = &active_head;
-        if ( (pinfo->next = active_head) != NULL )
-            pinfo->next->pprev = &pinfo->next;
-        active_head = pinfo;
+        PyErr_SetString(port_error, "no space to write request");
+        return NULL;
     }
 
-    return 1;
+    cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)];
+    memcpy(cmsg, &xum->msg, sizeof(*cmsg));
+
+    xup->rx_req_prod = cif->rx_req_prod = p + 1;
+
+    Py_INCREF(Py_None);
+    return Py_None;
 }
 
-static void process_channel(unsigned int port)
+static PyObject *xu_port_read_response(PyObject *self, PyObject *args)
 {
-    portinfo_t      *pinfo = &portinfo[port];
-    u16              wbuf = port;
+    xu_port_object    *xup = (xu_port_object *)self;
+    xu_message_object *xum;
+    CONTROL_RING_IDX   c = xup->rx_resp_cons;
+    control_if_t      *cif = xup->interface;
+    control_msg_t     *cmsg;
 
-    /* Acknowledge the notification. */
-    (void)write(evt_fd, &wbuf, sizeof(wbuf));
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
 
-    /* Process requests; send notification if we updated either ring. */
-    if ( process_evtchn_reads(pinfo) || process_evtchn_writes(pinfo) )
-        (void)xc_evtchn_send(xc_fd, port);
+    if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
+    {
+        PyErr_SetString(port_error, "no response to read");
+        return NULL;
+    }
+
+    cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)];
+    xum = PyObject_New(xu_message_object, &xu_message_type);
+    memcpy(&xum->msg, cmsg, sizeof(*cmsg));
+    if ( xum->msg.length > sizeof(xum->msg.msg) )
+        xum->msg.length = sizeof(xum->msg.msg);
+    xup->rx_resp_cons++;
+    return (PyObject *)xum;
 }
 
-int main(int argc, char **argv)
+static PyObject *xu_port_write_response(PyObject *self, PyObject *args)
 {
-    struct pollfd polls[1025]; /* one per port, plus /dev/xeno/evtchn */
-    portinfo_t *pinfo;
-    unsigned int batch, bytes, i, port, fd_idx;
-    u16 buf[BATCH_SIZE];
+    xu_port_object    *xup = (xu_port_object *)self;
+    xu_message_object *xum;
+    CONTROL_RING_IDX   p = xup->tx_resp_prod;
+    control_if_t      *cif = xup->interface;
+    control_msg_t     *cmsg;
 
-    /* Ignore writes to disconnected sockets. We clear up later. */
-    (void)signal(SIGPIPE, SIG_IGN);
-    
-    if ( (evt_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR)) == -1 )
-    {
-        SYS_ERROR("Could not open '%s'", EVTCHN_DEV_NAME);
-        ROOT_HINT();
-        HINT("On a non-devfs system you must run 'mknod %s c %d %d'.",
-             EVTCHN_DEV_NAME, EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR);
-        exit(1);
-    }
+    if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
+        return NULL;
 
-    if ( (mem_fd = open("/dev/mem", O_RDWR)) == -1 )
+    if ( !PyObject_TypeCheck((PyObject *)xum, &xu_message_type) )
     {
-        SYS_ERROR("Could not open '/dev/mem'");
-        ROOT_HINT();
-        exit(1);
+        PyErr_SetString(PyExc_TypeError, "expected a xend_utils.message");
+        return NULL;        
     }
 
-    if ( (xc_fd = xc_interface_open()) == -1 )
+    if ( p == xup->tx_req_cons )
     {
-        SYS_ERROR("Could not open Xen control interface");
-        ROOT_HINT();
-        DOM0_HINT();
-        exit(1);
+        PyErr_SetString(port_error, "no space to write response");
+        return NULL;
     }
 
-    for ( ; ; )
-    {
-        polls[0].fd     = evt_fd;
-        polls[0].events = POLLIN;
+    cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)];
+    memcpy(cmsg, &xum->msg, sizeof(*cmsg));
 
-        fd_idx = 1;
-        for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next )
-        {
-            switch ( pinfo->con_status )
-            {
-            case CONSTAT_LISTENING:
-                polls[fd_idx].fd     = pinfo->con_fd;
-                polls[fd_idx].events = POLLIN;
-                fd_idx++;
-                break;
-            case CONSTAT_CONNECTED:
-                polls[fd_idx].fd     = pinfo->con_fd;
-                polls[fd_idx].events = POLLIN | (RX_EMPTY(pinfo)?0:POLLOUT);
-                fd_idx++;
-                break;
-            }
-        }
+    xup->tx_resp_prod = cif->tx_resp_prod = p + 1;
 
-        while ( poll(polls, fd_idx, -1) == -1 )
-        {
-            if ( errno == EINTR )
-                continue;
-            SYS_ERROR("Unexpected error from poll().");
-            exit(1);
-        }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
 
-        fd_idx = 1;
-        for ( pinfo = active_head; pinfo != NULL; pinfo = pinfo->next )
-        {
-            switch ( pinfo->con_status )
-            {
-            case CONSTAT_LISTENING:
-                if ( ((polls[fd_idx].revents & POLLIN) != 0) )
-                    (void)make_consock_connected(pinfo);
-                break;
-            case CONSTAT_CONNECTED:
-                if ( ((polls[fd_idx].revents & POLLOUT) != 0) )
-                    do_consock_write(pinfo);
-                if ( ((polls[fd_idx].revents & POLLIN) != 0) )
-                    do_consock_read(pinfo);
-                break;
-            }
-            fd_idx++;
-        }
+static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args)
+{
+    xu_port_object    *xup = (xu_port_object *)self;
+    CONTROL_RING_IDX   c = xup->tx_req_cons;
+    control_if_t      *cif = xup->interface;
 
-        while ( (bytes = read(evt_fd, buf, sizeof(buf))) == -1 )
-        {
-            if ( errno == EINTR )
-                continue;
-            if ( errno == EAGAIN )
-            {
-                bytes = 0;
-                break;
-            }
-            SYS_ERROR("Unexpected error while reading '%s'.", EVTCHN_DEV_NAME);
-            exit(1);
-        }
-        
-        if ( bytes == 0 )
-            continue;
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
 
-        if ( (bytes & 1) != 0 )
-        {
-            ERROR("Bad read length (%d bytes) from '%s'.",
-                  bytes, EVTCHN_DEV_NAME);
-            exit(1);
-        }
-        
-        batch = bytes / sizeof(u16);
-        for ( i = 0; i < batch; i++ )
-        {
-            port = buf[i] & PORTIDX_MASK;
-            
-            if ( buf[i] & PORT_DISCONNECT )
-            {
-                DPRINTF("Disconnect on port %d.", port);
-                (void)handle_channel_exception(port);
-                continue;
-            }
-            
-            if ( portinfo[port].interface == NULL )
-            {
-                DPRINTF("Unexpected notification on port %d.", port);
-                if ( !handle_channel_exception(port) )
-                    continue;
-            }
-            
-            process_channel(port);
-        }
-    }
+    if ( (c == cif->tx_req_prod) || 
+         ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
+        return PyInt_FromLong(0);
+
+    return PyInt_FromLong(1);
+}
+
+static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args)
+{
+    xu_port_object    *xup = (xu_port_object *)self;
+    CONTROL_RING_IDX   p = xup->rx_req_prod;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
 
-    (void)xc_interface_close(xc_fd);
-    (void)close(mem_fd);
-    (void)close(evt_fd);
+    if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
+        return PyInt_FromLong(0);
 
-    return 0;
+    return PyInt_FromLong(1);
 }
 
+static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args)
+{
+    xu_port_object    *xup = (xu_port_object *)self;
+    CONTROL_RING_IDX   c = xup->rx_resp_cons;
+    control_if_t      *cif = xup->interface;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
+        return PyInt_FromLong(0);
 
-/* Returns non-zero if console is listening on exit. */
-static int make_consock_listener(portinfo_t *pinfo)
+    return PyInt_FromLong(1);
+}
+
+static PyObject *xu_port_space_to_write_response(
+    PyObject *self, PyObject *args)
 {
-    int reuseaddr_flag = 1;
-    struct linger linger;
-    int tcp_port = 9600 + PORT(pinfo);
-    int fd, flags;
-    struct sockaddr_in sa;
+    xu_port_object    *xup = (xu_port_object *)self;
+    CONTROL_RING_IDX   p = xup->tx_resp_prod;
 
-    if ( pinfo->con_status == CONSTAT_LISTENING )
-        return 1;
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
 
-    if ( pinfo->con_status == CONSTAT_CONNECTED )
-    {
-        (void)close(pinfo->con_fd);
-        pinfo->con_status = CONSTAT_CLOSED;
-    }
+    if ( p == xup->tx_req_cons )
+        return PyInt_FromLong(0);
+
+    return PyInt_FromLong(1);
+}
+
+static PyMethodDef xu_port_methods[] = {
+    { "notify",
+      (PyCFunction)xu_port_notify,
+      METH_VARARGS,
+      "Send a notification to the remote end.\n" },
+
+    { "read_request",
+      (PyCFunction)xu_port_read_request,
+      METH_VARARGS,
+      "Read a request message from the control interface.\n" },
+
+    { "write_request",
+      (PyCFunction)xu_port_write_request,
+      METH_VARARGS,
+      "Write a request message to the control interface.\n" },
+
+    { "read_response",
+      (PyCFunction)xu_port_read_response,
+      METH_VARARGS,
+      "Read a response message from the control interface.\n" },
+
+    { "write_response",
+      (PyCFunction)xu_port_write_response,
+      METH_VARARGS,
+      "Write a response message to the control interface.\n" },
+
+    { "request_to_read",
+      (PyCFunction)xu_port_request_to_read,
+      METH_VARARGS,
+      "Returns TRUE if there is a request message to read.\n" },
+
+    { "space_to_write_request",
+      (PyCFunction)xu_port_space_to_write_request,
+      METH_VARARGS,
+      "Returns TRUE if there is space to write a request message.\n" },
+
+    { "response_to_read",
+      (PyCFunction)xu_port_response_to_read,
+      METH_VARARGS,
+      "Returns TRUE if there is a response message to read.\n" },
+
+    { "space_to_write_response",
+      (PyCFunction)xu_port_space_to_write_response,
+      METH_VARARGS,
+      "Returns TRUE if there is space to write a response message.\n" },
+
+    { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_port_type;
+
+static PyObject *xu_port_new(PyObject *self, PyObject *args)
+{
+    xu_port_object *xup;
+    u64 dom;
+    int port1, port2;
+    xc_dominfo_t info;
+
+    if ( !PyArg_ParseTuple(args, "L", &dom) )
+        return NULL;
+
+    xup = PyObject_New(xu_port_object, &xu_port_type);
 
-    if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
+    if ( (xup->mem_fd = open("/dev/mem", O_RDWR)) == -1 )
     {
-        SYS_ERROR("Could not create TCP socket.");
-        return 0;
+        PyErr_SetString(port_error, "Could not open '/dev/mem'");
+        goto fail1;
     }
 
-    linger.l_onoff = 0;
-    if ( (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
-                     &reuseaddr_flag, sizeof(int)) != 0) ||
-         (setsockopt(fd, SOL_SOCKET, SO_LINGER, 
-                     &linger, sizeof(linger)) != 0) )
+    if ( (xup->xc_handle = xc_interface_open()) == -1 )
     {
-        SYS_ERROR("Could not enable immediate reuse of socket port.");
-        close(fd);
-        return 0;
+        PyErr_SetString(port_error, "Could not open Xen control interface");
+        goto fail2;
     }
 
-    sa.sin_family      = AF_INET;
-    sa.sin_addr.s_addr = htonl(INADDR_ANY);
-    sa.sin_port        = htons(tcp_port);
-    if ( bind(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0 )
+    if ( xc_evtchn_open(xup->xc_handle, DOMID_SELF, dom, &port1, &port2) != 0 )
     {
-        SYS_ERROR("Unable to bind to console port %d.", tcp_port);
-        close(fd);
-        return 0;
+        PyErr_SetString(port_error, "Could not open channel to domain");
+        goto fail3;
     }
 
-    if ( listen(fd, 5) != 0 )
+    if ( (xc_domain_getinfo(xup->xc_handle, dom, 1, &info) != 1) ||
+         (info.domid != dom) )
     {
-        SYS_ERROR("Unable to listen on console port %d.", tcp_port);
-        close(fd);
-        return 0;
+        PyErr_SetString(port_error, "Failed to obtain domain status");
+        goto fail4;
     }
 
-    if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
-         (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) )
+    xup->interface = 
+        map_control_interface(xup->mem_fd, info.shared_info_frame);
+    if ( xup->interface == NULL )
     {
-        SYS_ERROR("Unable to set non-blocking status for console listener.");
-        close(fd);
-        return 0;
+        PyErr_SetString(port_error, "Failed to map domain control interface");
+        goto fail4;
     }
 
-    pinfo->con_fd     = fd;
-    pinfo->con_status = CONSTAT_LISTENING;
-    return 1;
+    xup->tx_req_cons  = 0;
+    xup->tx_resp_prod = 0;
+    xup->rx_req_prod  = 0;
+    xup->rx_resp_cons = 0;
+    xup->remote_dom   = dom;
+    xup->local_port   = port1;
+    xup->remote_port  = port2;
+
+    return (PyObject *)xup;
+
+    
+ fail4:
+    (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1);
+ fail3:
+    (void)xc_interface_close(xup->xc_handle);
+ fail2:
+    (void)close(xup->mem_fd);
+ fail1:
+    PyObject_Del((PyObject *)xup);
+    return NULL;        
 }
 
-/* Returns non-zero if console is connected on exit. */
-static int make_consock_connected(portinfo_t *pinfo)
+static PyObject *xu_port_getattr(PyObject *obj, char *name)
 {
-    int fd, flags, sa_len;
-    struct linger linger;
-    struct sockaddr_in sa;
+    xu_port_object *xup = (xu_port_object *)obj;
+    if ( strcmp(name, "local_port") == 0 )
+        return PyInt_FromLong(xup->local_port);
+    if ( strcmp(name, "remote_port") == 0 )
+        return PyInt_FromLong(xup->remote_port);
+    if ( strcmp(name, "remote_dom") == 0 )
+        return PyLong_FromUnsignedLongLong(xup->remote_dom);
+    return Py_FindMethod(xu_port_methods, obj, name);
+}
 
-    if ( pinfo->con_status == CONSTAT_CONNECTED )
-        return 1;
+static void xu_port_dealloc(PyObject *self)
+{
+    xu_port_object *xup = (xu_port_object *)self;
+    unmap_control_interface(xup->mem_fd, xup->interface);
+    (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port);
+    (void)xc_interface_close(xup->xc_handle);
+    (void)close(xup->mem_fd);
+    PyObject_Del(self);
+}
 
-    if ( pinfo->con_status == CONSTAT_CLOSED )
-        return 0;
+static PyTypeObject xu_port_type = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,
+    "port",
+    sizeof(xu_port_object),
+    0,
+    xu_port_dealloc,     /* tp_dealloc     */
+    NULL,                /* tp_print       */
+    xu_port_getattr,     /* tp_getattr     */
+    NULL,                /* tp_setattr     */
+    NULL,                /* tp_compare     */
+    NULL,                /* tp_repr        */
+    NULL,                /* tp_as_number   */
+    NULL,                /* tp_as_sequence */
+    NULL,                /* tp_as_mapping  */
+    NULL                 /* tp_hash        */
+};
+
+
+
+/*
+ * *********************** BUFFER ***********************
+ */
 
-    if ( (fd = accept(pinfo->con_fd, (struct sockaddr *)&sa, &sa_len)) == -1 )
-        return 0;
+#define BUFSZ 65536
+#define MASK_BUF_IDX(_i) ((_i)&(BUFSZ-1))
+typedef unsigned int BUF_IDX;
 
-    linger.l_onoff = 0;
-    if ( setsockopt(fd, SOL_SOCKET, SO_LINGER, 
-                    &linger, sizeof(linger)) != 0 )
-    {
-        SYS_ERROR("Could not enable immediate socket death.");
-        close(fd);
-        return 0;
-    }
+typedef struct {
+    PyObject_HEAD;
+    char        *buf;
+    unsigned int prod, cons;
+} xu_buffer_object;
 
-    if ( ((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
-         (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) )
+static PyObject *__xu_buffer_peek(xu_buffer_object *xub, int max)
+{
+    PyObject *str1, *str2;
+    int len1, len2, c = MASK_BUF_IDX(xub->cons);
+
+    len1 = xub->prod - xub->cons;
+    if ( len1 > (BUFSZ - c) ) /* clip to ring wrap */
+        len1 = BUFSZ - c;
+    if ( len1 > max )         /* clip to specified maximum */
+        len1 = max;
+    if ( len1 < 0 )           /* sanity */
+        len1 = 0;
+
+    if ( (str1 = PyString_FromStringAndSize(&xub->buf[c], len1)) == NULL )
+        return NULL;
+
+    if ( (len1 < (xub->prod - xub->cons)) && (len1 < max) )
     {
-        SYS_ERROR("Unable to set non-blocking status on socket.");
-        close(fd);
-        return 0;
+        len2 = max - len1;
+        if ( len2 > MASK_BUF_IDX(xub->prod) )
+            len2 = MASK_BUF_IDX(xub->prod);
+        if ( len2 > 0 )
+        {
+            str2 = PyString_FromStringAndSize(&xub->buf[0], len2);
+            if ( str2 == NULL )
+                return NULL;
+            PyString_ConcatAndDel(&str1, str2);
+            if ( str1 == NULL )
+                return NULL;
+        }
     }
 
-    (void)close(pinfo->con_fd);
-
-    pinfo->con_fd     = fd;
-    pinfo->con_status = CONSTAT_CONNECTED;
-    return 1;
+    return str1;
 }
 
+static PyObject *xu_buffer_peek(PyObject *self, PyObject *args)
+{
+    xu_buffer_object *xub = (xu_buffer_object *)self;
+    int max = 1024;
 
-static void make_consock_closed(portinfo_t *pinfo)
+    if ( !PyArg_ParseTuple(args, "|i", &max) )
+        return NULL;
+    
+    return __xu_buffer_peek(xub, max);
+}
+
+static PyObject *xu_buffer_read(PyObject *self, PyObject *args)
 {
-    if ( pinfo->con_status != CONSTAT_CLOSED )
-        (void)close(pinfo->con_fd);
-    pinfo->con_status = CONSTAT_CLOSED;
+    xu_buffer_object *xub = (xu_buffer_object *)self;
+    PyObject *str;
+    int max = 1024;
+
+    if ( !PyArg_ParseTuple(args, "|i", &max) )
+        return NULL;
+
+    if ( (str = __xu_buffer_peek(xub, max)) != NULL )
+        xub->cons += PyString_Size(str);
+
+    return str;
 }
 
+static PyObject *xu_buffer_discard(PyObject *self, PyObject *args)
+{
+    xu_buffer_object *xub = (xu_buffer_object *)self;
+    int max, len;
+
+    if ( !PyArg_ParseTuple(args, "i", &max) )
+        return NULL;
+
+    len = xub->prod - xub->cons;
+    if ( len > max )
+        len = max;
+    if ( len < 0 )
+        len = 0;
+
+    xub->cons += len;
+
+    return PyInt_FromLong(len);
+}
 
-static void do_consock_read(portinfo_t *pinfo)
+static PyObject *xu_buffer_write(PyObject *self, PyObject *args)
 {
-    char buf[1024];
-    int  idx, bytes, rc, was_empty = TX_EMPTY(pinfo);
+    xu_buffer_object *xub = (xu_buffer_object *)self;
+    char *str;
+    int len, len1, len2;
 
-    while ( (rc = read(pinfo->con_fd, &buf, sizeof(buf))) > 0 )
-    {
-        idx = 0;
-        while ( (rc != 0) && !TX_FULL(pinfo) )
-        {
-            bytes = rc;
-            /* Clip copy to ring-buffer wrap. */
-            if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp)) )
-                bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txp);
-            /* Clip copy to ring-buffer overflow. */
-            if ( bytes > (CONBUFSZ - (pinfo->txp - pinfo->txc)) )
-                bytes = CONBUFSZ - (pinfo->txp - pinfo->txc);
-            memcpy(&pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txp)],
-                   &buf[idx], bytes);
-            pinfo->txp += bytes;
-            idx        += bytes;
-            rc         -= bytes;
-        }
-    }
+    if ( !PyArg_ParseTuple(args, "s#", &str, &len) )
+        return NULL;
+
+    len1 = len;
+    if ( len1 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
+        len1 = BUFSZ - MASK_BUF_IDX(xub->prod);
+    if ( len1 > (BUFSZ - (xub->prod - xub->cons)) )
+        len1 = BUFSZ - (xub->prod - xub->cons);
+
+    if ( len1 == 0 )
+        return PyInt_FromLong(0);
 
-    if ( (rc == 0) || (errno != EAGAIN) )
+    memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[0], len1);
+    xub->prod += len1;
+
+    if ( len1 < len )
     {
-        DPRINTF("Console client has disconnected.");
-        if ( !make_consock_listener(pinfo) )
+        len2 = len - len1;
+        if ( len2 > (BUFSZ - MASK_BUF_IDX(xub->prod)) )
+            len2 = BUFSZ - MASK_BUF_IDX(xub->prod);
+        if ( len2 > (BUFSZ - (xub->prod - xub->cons)) )
+            len2 = BUFSZ - (xub->prod - xub->cons);
+        if ( len2 != 0 )
         {
-            ERROR("Could not revert console %d to listener status.",
-                  PORT(pinfo));
-            exit(1);
+            memcpy(&xub->buf[MASK_BUF_IDX(xub->prod)], &str[len1], len2);
+            xub->prod += len2;
+            return PyInt_FromLong(len1 + len2);
         }
     }
 
-    if ( was_empty && !TX_EMPTY(pinfo) )
-    {
-        /* There is now data to transmit to guest. Kickstart the pipeline. */
-        if ( process_evtchn_writes(pinfo) )
-            (void)xc_evtchn_send(xc_fd, PORT(pinfo));
-    }
+    return PyInt_FromLong(len1);
 }
 
-static void do_consock_write(portinfo_t *pinfo)
+static PyObject *xu_buffer_empty(PyObject *self, PyObject *args)
 {
-    int bytes, rc;
+    xu_buffer_object *xub = (xu_buffer_object *)self;
 
-    while ( !RX_EMPTY(pinfo) )
-    {
-        /* Clip transfer to ring-buffer wrap. */
-        bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxc);
-        /* Clip transfer to ring-buffer overflow. */
-        if ( bytes > (pinfo->rxp - pinfo->rxc) )
-            bytes = pinfo->rxp - pinfo->rxc;
-        rc = write(pinfo->con_fd, 
-                   &pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxc)], 
-                   bytes);
-        if ( rc <= 0 )
-            return; /* Nothing to do. Errors cleaned up in reader code. */
-        pinfo->rxc += rc;
-    }
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    if ( xub->cons == xub->prod )
+        return PyInt_FromLong(1);
+
+    return PyInt_FromLong(0);
 }
 
-static int process_evtchn_reads(portinfo_t *pinfo)
+static PyObject *xu_buffer_full(PyObject *self, PyObject *args)
 {
-    CONTROL_RING_IDX c;
-    control_if_t    *cif = pinfo->interface;
-    control_msg_t   *cmsg;
-    unsigned int     clen, idx, len, bytes;
+    xu_buffer_object *xub = (xu_buffer_object *)self;
 
-    for ( c = pinfo->tx_req_cons; 
-          (c != cif->tx_req_prod) && 
-              ((c-pinfo->tx_resp_prod) != CONTROL_RING_SIZE);
-          c++ )
-    {
-        cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)];
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
 
-        if ( (clen = cmsg->length) > sizeof(cmsg->msg) )
-            clen = sizeof(cmsg->msg);
+    if ( (xub->prod - xub->cons) == BUFSZ )
+        return PyInt_FromLong(1);
 
-        if ( (cmsg->cmd_type == CMD_CONSOLE) &&
-             (cmsg->cmd_subtype == CMD_CONSOLE_DATA) )
-        {
-            idx = 0;
-            len = cmsg->length;
-            while ( (len != 0) && !RX_FULL(pinfo) )
-            {
-                bytes = len;
-                /* Clip copy to ring-buffer wrap. */
-                if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp)) )
-                    bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->rxp);
-                /* Clip copy to ring-buffer overflow. */
-                if ( bytes > (CONBUFSZ - (pinfo->rxp - pinfo->rxc)) )
-                    bytes = CONBUFSZ - (pinfo->rxp - pinfo->rxc);
-                memcpy(&pinfo->rx_buf[MASK_CONBUF_IDX(pinfo->rxp)],
-                       &cmsg->msg[idx], bytes);
-                pinfo->rxp += bytes;
-                idx += bytes;
-                len -= bytes;
-            }
-        }
+    return PyInt_FromLong(0);
+}
 
-        /* Prepare response. No payload; msg type and id same as request. */
-        cmsg->length = 0;
-    }
+static PyMethodDef xu_buffer_methods[] = {
+    { "peek", 
+      (PyCFunction)xu_buffer_peek,
+      METH_VARARGS,
+      "Peek up to @max bytes from the buffer. Returns a string.\n" },
 
-    if ( c != pinfo->tx_req_cons )
+    { "read", 
+      (PyCFunction)xu_buffer_read,
+      METH_VARARGS,
+      "Read up to @max bytes from the buffer. Returns a string.\n" },
+
+    { "discard", 
+      (PyCFunction)xu_buffer_discard,
+      METH_VARARGS,
+      "Discard up to @max bytes from the buffer. Returns number of bytes.\n" },
+
+    { "write", 
+      (PyCFunction)xu_buffer_write,
+      METH_VARARGS,
+      "Write @string into buffer. Return number of bytes written.\n" },
+
+    { "empty", 
+      (PyCFunction)xu_buffer_empty,
+      METH_VARARGS,
+      "Return TRUE if the buffer is empty.\n" },
+
+    { "full", 
+      (PyCFunction)xu_buffer_full,
+      METH_VARARGS,
+      "Return TRUE if the buffer is full.\n" },
+
+    { NULL, NULL, 0, NULL }
+};
+
+staticforward PyTypeObject xu_buffer_type;
+
+static PyObject *xu_buffer_new(PyObject *self, PyObject *args)
+{
+    xu_buffer_object *xub;
+
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
+
+    xub = PyObject_New(xu_buffer_object, &xu_buffer_type);
+
+    if ( (xub->buf = malloc(BUFSZ)) == NULL )
     {
-        /* Update private indexes. */
-        pinfo->tx_resp_prod = c;
-        pinfo->tx_req_cons  = c;
-        /* Queue responses and send a notification to the guest OS. */
-        cif->tx_resp_prod   = c;
-        return 1;
+        PyObject_Del((PyObject *)xub);
+        return NULL;
     }
 
-    return 0;
+    xub->prod = xub->cons = 0;
+
+    return (PyObject *)xub;
+}
+
+static PyObject *xu_buffer_getattr(PyObject *obj, char *name)
+{
+    return Py_FindMethod(xu_buffer_methods, obj, name);
+}
+
+static void xu_buffer_dealloc(PyObject *self)
+{
+    xu_buffer_object *xub = (xu_buffer_object *)self;
+    free(xub->buf);
+    PyObject_Del(self);
 }
 
-static int process_evtchn_writes(portinfo_t *pinfo)
+static PyTypeObject xu_buffer_type = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,
+    "buffer",
+    sizeof(xu_buffer_object),
+    0,
+    xu_buffer_dealloc,   /* tp_dealloc     */
+    NULL,                /* tp_print       */
+    xu_buffer_getattr,   /* tp_getattr     */
+    NULL,                /* tp_setattr     */
+    NULL,                /* tp_compare     */
+    NULL,                /* tp_repr        */
+    NULL,                /* tp_as_number   */
+    NULL,                /* tp_as_sequence */
+    NULL,                /* tp_as_mapping  */
+    NULL                 /* tp_hash        */
+};
+
+
+
+/*
+ * *********************** MODULE WRAPPER ***********************
+ */
+
+static void handle_child_death(int dummy)
 {
-    CONTROL_RING_IDX p, rx_resp_prod;
-    control_if_t    *cif = pinfo->interface;
-    control_msg_t   *cmsg;
-    unsigned int     bytes;
+    while ( waitpid(-1, NULL, WNOHANG) > 0 )
+        continue;
+}
 
-    /* Validate the rx-response producer, an dupdate our consumer if okay. */
-    rx_resp_prod = cif->rx_resp_prod;
-    if ( (pinfo->rx_resp_cons != rx_resp_prod) &&
-         ((pinfo->rx_req_prod - rx_resp_prod) <= CONTROL_RING_SIZE) &&
-         ((rx_resp_prod - pinfo->rx_resp_cons) <= CONTROL_RING_SIZE) )
-        pinfo->rx_resp_cons = cif->rx_resp_prod;
+static PyObject *xu_autoreap(PyObject *self, PyObject *args)
+{
+    struct sigaction sa;
 
-    for ( p = pinfo->rx_req_prod;
-          (p-pinfo->rx_resp_cons) != CONTROL_RING_SIZE;
-          p++ )
-    {
-        if ( TX_EMPTY(pinfo) )
-            break;
-        cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)];
-        bytes = sizeof(cmsg->msg);
-        /* Clip transfer to ring-buffer wrap. */
-        if ( bytes > (CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc)) )
-            bytes = CONBUFSZ - MASK_CONBUF_IDX(pinfo->txc);
-        /* Clip transfer to ring-buffer overflow. */
-        if ( bytes > (pinfo->txp - pinfo->txc) )
-            bytes = pinfo->txp - pinfo->txc;
-        cmsg->cmd_type    = CMD_CONSOLE;
-        cmsg->cmd_subtype = CMD_CONSOLE_DATA;
-        cmsg->id          = 0xaa;
-        cmsg->length      = bytes;
-        memcpy(&cmsg->msg[0], 
-               &pinfo->tx_buf[MASK_CONBUF_IDX(pinfo->txc)], 
-               bytes);
-        pinfo->txc += bytes;
-    }
+    if ( !PyArg_ParseTuple(args, "") )
+        return NULL;
 
-    if ( p != pinfo->rx_req_prod )
-    {
-        pinfo->rx_req_prod  = p;
-        cif->rx_req_prod    = p;
-        return 1;
-    }
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_handler = handle_child_death;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+    (void)sigaction(SIGCHLD, &sa, NULL);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyMethodDef xu_methods[] = {
+    { "notifier", xu_notifier_new, METH_VARARGS, 
+      "Create a new notifier." },
+    { "message", xu_message_new, METH_VARARGS, 
+      "Create a new communications message." },
+    { "port", xu_port_new, METH_VARARGS, 
+      "Create a new communications port." },
+    { "buffer", xu_buffer_new, METH_VARARGS, 
+      "Create a new ring buffer." },
+    { "autoreap", xu_autoreap, METH_VARARGS,
+      "Ensure that zombie children are automatically reaped by the OS." },
+    { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC initxend_utils(void)
+{
+    PyObject *m, *d;
+
+    m = Py_InitModule("xend_utils", xu_methods);
 
-    return 0;
+    d = PyModule_GetDict(m);
+    port_error = PyErr_NewException("xend_utils.PortError", NULL, NULL);
+    PyDict_SetItemString(d, "PortError", port_error);
 }
index 2e85fcbe1ae6bdab217cc990afe90391dbff8e0d..11beb34cd675ca16c794f90f99ff47e52b8d5d95 100644 (file)
@@ -14,18 +14,22 @@ MAN8     = $(wildcard *.8)
 all: $(BIN)
 
 install: all
-       mkdir -p /usr/bin
-       cp $(BIN) /usr/bin
-       for i in $(BIN); do chmod 755 /usr/bin/$$i; done
-       for i in $(MAN1); do cp $$i /usr/man/man1/$$i; done
-       for i in $(MAN8); do cp $$i /usr/man/man8/$$i; done
+       mkdir -p $(prefix)/usr/bin
+       mkdir -p $(prefix)/usr/man/man1
+       mkdir -p $(prefix)/usr/man/man8
+       cp $(BIN) $(prefix)/usr/bin
+       for i in $(BIN); do chmod 755 $(prefix)/usr/bin/$$i; done
+       for i in $(MAN1); do cp $$i $(prefix)/usr/man/man1/$$i; done
+       for i in $(MAN8); do cp $$i $(prefix)/usr/man/man8/$$i; done
 
 dist: all
        mkdir -p ../../../install/bin
+       mkdir -p ../../../install/man/man1
+       mkdir -p ../../../install/man/man8
        cp $(BIN) ../../../install/bin
-       chmod 755 ../../../install/bin/$(BIN)
-       cp $(SCRIPTS) ../../../install/bin
-       for i in $(SCRIPTS); do chmod 755 ../../../install/bin/$i; done
+       for i in $(BIN); do chmod 755 ../../../install/bin/$$i; done
+       for i in $(MAN1); do cp $$i ../../../install/man/man1/$$i; done
+       for i in $(MAN8); do cp $$i ../../../install/man/man8/$$i; done
 
 clean:
        $(RM) *.a *.so *.o *.rpm $(BIN)
index 367b9b4f0e302a0566bffaea4fdf4580a31e717b..4d42d8d9da91f23feeba32166e73a357ed31f7d7 100644 (file)
@@ -52,9 +52,9 @@ static void nonpriv_conwrite(const char *s, unsigned int count)
 
         p = MASK_CONTROL_IDX(ctrl_if->tx_req_prod);
         
-        ctrl_if->tx_ring[p].cmd_type    = CMD_CONSOLE;
-        ctrl_if->tx_ring[p].cmd_subtype = CMD_CONSOLE_DATA;
-        ctrl_if->tx_ring[p].id          = 0xaa;
+        ctrl_if->tx_ring[p].type    = CMSG_CONSOLE;
+        ctrl_if->tx_ring[p].subtype = CMSG_CONSOLE_DATA;
+        ctrl_if->tx_ring[p].id      = 0xaa;
         src = dst = 0;
         while ( (src < count) && (dst < (sizeof(ctrl_if->tx_ring[p].msg)-1)) )
         {
@@ -202,8 +202,8 @@ static void __do_console_io(void)
     for ( c = ctrl_if->rx_resp_prod; c != ctrl_if->rx_req_prod; c++ )
     {
         msg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(c)];
-        if ( (msg->cmd_type == CMD_CONSOLE) &&
-             (msg->cmd_subtype == CMD_CONSOLE_DATA) )
+        if ( (msg->type == CMSG_CONSOLE) &&
+             (msg->subtype == CMSG_CONSOLE_DATA) )
         {
             for ( i = 0; i < msg->length; i++ )
                 tty_insert_flip_char(xeno_console_tty, msg->msg[i], 0);
@@ -225,9 +225,9 @@ static void __do_console_io(void)
         if ( (wc == wp) && (x_char == 0) )
             break;
         msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(c)];
-        msg->cmd_type    = CMD_CONSOLE;
-        msg->cmd_subtype = CMD_CONSOLE_DATA;
-        msg->id          = 0xaa;
+        msg->type    = CMSG_CONSOLE;
+        msg->subtype = CMSG_CONSOLE_DATA;
+        msg->id      = 0xaa;
         len = 0;
         if ( x_char != 0 ) /* Handle XON/XOFF urgently. */
         {
index aa8375e729c2b241fe782493ed6c8ddcbe628f91..dd15a96bff13161f056e50c762c15aed581b61d9 100644 (file)
@@ -8,11 +8,11 @@
 #define __CONTROL_IF_H__
 
 typedef struct {
-    u8 cmd_type;     /* echoed in response */
-    u8 cmd_subtype;  /* echoed in response */
-    u8 id;           /* echoed in response */
-    u8 length;       /* number of bytes in 'msg' */
-    unsigned char msg[60]; /* command-specific message data */
+    u8 type;     /* echoed in response */
+    u8 subtype;  /* echoed in response */
+    u8 id;       /* echoed in response */
+    u8 length;   /* number of bytes in 'msg' */
+    unsigned char msg[60]; /* type-specific message data */
 } control_msg_t;
 
 #define CONTROL_RING_SIZE 8
@@ -26,7 +26,7 @@ typedef struct {
     CONTROL_RING_IDX rx_req_prod, rx_resp_prod;
 } control_if_t;
 
-#define CMD_CONSOLE      0
-#define CMD_CONSOLE_DATA 0
+#define CMSG_CONSOLE      0
+#define CMSG_CONSOLE_DATA 0
 
 #endif /* __CONTROL_IF_H__ */